package psim;

import java.lang.reflect.InvocationTargetException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Trida threads, ktera je instanciovana tolikrat,
 * kolik je procesoru k dispozici
 * @author Tomas Drimal
 */
class ThreadPtcs extends Thread {
    //dolni hranice intervalu vypoctu
    int from;
    //horni hranice intrevalu vypoctu
    int to;

    /**
     * Kostruktor teto tridy
     * @param name jmeno threads
     * @param from dolni hranice intervalu, pro ktery bude tato instance pocitat
     * @param to horni hranice intervalu, pro ktery bude tato instance pocitat
     */
    public ThreadPtcs(String name, int from, int to) {
        super(name);
        this.from = from;
        this.to = to;
    }

    /**
     * Metoda run, obsahuje vykonnou cast tohoto threads
     */
    @Override
    public void run() {
        try {
            Main.particles.chPosFT(this.from, this.to);
        } catch (NoSuchMethodException ex) {
            Logger.getLogger(ThreadPtcs.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(ThreadPtcs.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (IllegalArgumentException ex) {
            Logger.getLogger(ThreadPtcs.class.getName()).log(Level.SEVERE,
                    null, ex);
        } catch (InvocationTargetException ex) {
            Logger.getLogger(ThreadPtcs.class.getName()).log(Level.SEVERE,
                    null, ex);
        }

    }
}

/**
 * Trida, ktera dedi vlastnosti tridy PtcsBase a rozsiruje je pro praci s vice
 * vlakny
 * @author Tomas Drimal
 */
public class PtcsMulti extends PtcsBase {
    //pole vlaken
    private ThreadPtcs threads[];
    //pole intervalu, aby se meze nemusely pocitat stale dokola
    private int intervals[][];
    //pocet CPU k dispozici
    private int CPUnr;

    //konstruktor
    public PtcsMulti(int CPUnr) {
        //rodicovky konstruktor
        super();
        this.CPUnr = CPUnr;
        //pocet vlaken podle poctu procesoru
        threads = new ThreadPtcs[CPUnr];
    }

    /*
     * Metoda, ktera rozdeluje vypocet na vice procesoru
     */
    public void chPos() {
//        System.out.println("Vice procesoru");
            //start vlaken
            for (int i = 0; i < threads.length; i++) {
                 //instancizace threads
                threads[i] = new ThreadPtcs("Thread",
                        intervals[i][0], intervals[i][1]);
                //start threads
                threads[i].start();
            }
            //cekani na ukonceni cinnosti vlaken
            try {
                for (int i = 0; i < threads.length; i++) {
                    threads[i].join();
                }
            } catch (InterruptedException ex) {
                Logger.getLogger(PtcsMulti.class.getName()).log(Level.SEVERE,
                        null, ex);
            }
            this.saveNew(); //ulozeni novych hodnot do starych
            Main.cykly++;
    }

    /*
     * Metoda, ktera pocita intervaly v zavislosti na poctu procesoru a
     * poctu castic
     */
    public void computeIntervals() {
        //vypocet hranic intervalu pro rozdeleni castic na procesory
        intervals = new int[CPUnr][2]; //inicializace pole
        double tmp = 0;
        intervals[0][0] = 0;
        intervals[0][1] = (int) (partcs.size() * (1 -
                (Math.sqrt((Double.valueOf(CPUnr) - 1) / CPUnr))));

        for (int i = 1; i < CPUnr; i++) {
            intervals[i][0] = intervals[i - 1][1];
            tmp = partcs.size() * (1 - (Math.sqrt((Double.valueOf(CPUnr)
                    - (i + 1)) / CPUnr)));
            intervals[i][1] = (int) (tmp);
        }
    }

    /**
     * Pretizeni metody z rodicovske tridy. Jednak vola metodu nacteni
     * castic ze tridy PtcsBase a pak pocita intervaly pro ucely
     * multitaskingu
     * @param filename name pts souboru s ulozenymi casticemi
     * @return true, jestli nedoslo k chybe
     */
    @Override
    public boolean LoadFromFile(String filename) {
        if (LoadFrFile(filename)) {
            computeIntervals();
            return true;
        } else {
            return false;
        }
    }
}
